package com.zzg.algorithm.prim.tree;

import com.zzg.algorithm.prim.entity.MGraph;

import java.util.Arrays;

/**
 * @Author zhengzg
 * @Date 2022-10-10
 * @Version v1.0
 * 最小生成树
 * 修路问题本质就是就是最小生成树问题， 先介绍一下最小生成树(Minimum Cost Spanning Tree)，简称 MST。
 * 给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树
 * 1) N 个顶点，一定有 N-1 条边
 * 2) 包含全部顶点
 * 3) N-1 条边都在图中
 */
public class MinTree {
    /**
     * 创建图的邻接矩阵
     * @param graph 图对象
     * @param verxs 图对应的顶点个数
     * @param data  图的各个顶点的值
     * @param weight 图的邻接矩阵
     */
    public void createGraph(MGraph graph,int verxs,char[] data,int[][] weight) {
        int i,j;
        for (i = 0; i < verxs; i++) {
            graph.data[i] = data[i];
            for (j = 0; j < verxs; j++) {
                graph.weight[i][j] = weight[i][j];
            }
        }
    }

    // 显示图的邻接矩阵
    public void showGraph(MGraph graph) {
        for (int[] link : graph.weight) {
            System.out.println(Arrays.toString(link));
        }
    }

    /**
     * 编写prim算法，得到最小生成树
     * @param graph 图
     * @param v 表示从第几个顶点开始
     */
    public void prim(MGraph graph, int v) {
        // visited[] 标记顶点是否被访问
        int[] visited = new int[graph.verxs];
        // 把当前结点设置为已经访问
        visited[v] = 1;
        // h1和h2记录两个顶点的下标
        int h1 = -1;
        int h2 = -1;
        // 表示两个顶点之间的路不通
        int minWeight = 10000;
        // 因为一共有graph.verxs个顶点，根据最小生成树原理，需要遍历graph.verxs - 1条边
        for (int k = 1; k < graph.verxs; k++) {
            // 确定每一次生成的子图，和那个结点的距离最近
            // i表示已经被访问的点
            for (int i = 0; i < graph.verxs; i++) {
                // j表示未被访问的点
                for (int j = 0; j < graph.verxs; j++) {
                    if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight) {
                        minWeight = graph.weight[i][j];
                        h1 = i;
                        // 记录下顶点的坐标
                        h2 = j;
                    }
                }
            }
            // 找到一条边最小
            System.out.println("边<" + graph.data[h1] + "," + graph.data[h2] + "> 权值：" + minWeight);
            // 将当前这个结点标记为已经访问
            visited[h2] = 1;
            // 重新将minWeight设置为10000
            minWeight = 10000;
        }

    }
}
